AddCSLuaFile()
---- _____  _____   _____ _____  __  __ ----
----|  __ \|  __ \ / ____|  __ \|  \/  |----
----| |__) | |__) | |  __| |  | | \  / |----
----|  _  /|  ___/| | |_ | |  | | |\/| |----
----| | \ \| |    | |__| | |__| | |  | |----
----|_|  \_\_|     \_____|_____/|_|  |_|----
--------------------------------------------
-------------[NEXTBOT NPC base]-------------
--------------------------------------------

if ( SERVER ) then
	--nothing yet
end
 
 
ENT.Base             = "base_nextbot_rpgdm"
ENT.Spawnable        = true
ENT.Vendor = false
ENT.VendorType = "preset"
ENT.RandomName = true
ENT.Aggressive = true
ENT.InCombat = false
ENT.AttackSpeed = 1.2
ENT.NextAttack = 1.2
ENT.SpellCaster = false
ENT.MinDamage = 10
ENT.MaxDamage = 15
ENT.Armor = 0
ENT.Model = "models/devin/rpgdm/testplayer.mdl"
ENT.EngagePos = Vector(0, 0, 0)
ENT.EngageAngle = Angle(0, 0, 0)
ENT.SpawnPos = Vector(0, 0, 0)
ENT.HealthMax = 35
ENT.IsPet = false
ENT.InteractDistance = 128
ENT.RareLevel = 0
ENT.RunSpeed = 200
ENT.Speed = 200
ENT.ReturnSpeed = 400
ENT.AggroRadius = 192
ENT.DistanceFromPlayer = 128
ENT.Threat = {}
ENT.Killable = false
ENT.Idle = true
ENT.Returning = false
ENT.FoundKillTarget = false
ENT.Faction = 0
ENT.Target = nil
ENT.HeldWeapon = nil
ENT.MainWeapon = ""
ENT.OffWeapon = ""
ENT.VendorHitBox = nil
ENT.IdleSoundFile = ""
ENT.Target = nil
ENT.Scale = 0.9
ENT.NextSpell = 0
ENT.Dead = false
ENT.IdleAnim = ACT_HL2MP_IDLE_MELEE2
ENT.RunAnim = ACT_HL2MP_RUN_MELEE2
ENT.AttackAnim = ACT_HL2MP_GESTURE_RANGE_ATTACK_MELEE2
ENT.WalkAnim = ACT_HL2MP_WALK
ENT.Spells = {}
ENT.Wander = false
ENT.Name = "Default Name"
ENT.XP = 50


ENT.FirstNames = {
"Buttcheeks",
"Smelly",
"Cock",
"Moist",
"Uncle",
"Sergeant",
"Sticky",
"Marshal",
"Warlord",
"Old Sir",
"Sweaty",
"Clammy",
"Grommash",
"Varian",
"Carlos",
"Tyrone",
"David",
"Dat"
}

ENT.LastNames = {
"Cock",
"Dong Fondler",
"the Rapist",
"Coleslaw",
"Asscrack",
"Dickcheese",
"Cunt",
"Phallus",
"Dick",
"Buttcheeks",
"Asscheeks",
}

ENT.Gear = {
4,
5,
6
}
ENT.tempEquippedItems = {}

ENT.AttackSounds = {
	Sound("devin/blackbetty/weapons/autoattack/m1hSwordHitFlesh1a.wav"),
	Sound("devin/blackbetty/weapons/autoattack/m1hSwordHitFlesh1b.wav"),
	Sound("devin/blackbetty/weapons/autoattack/m1hSwordHitFlesh1c.wav")
}

ENT.WeaponSounds = {
	Sound("devin/blackbetty/weapons/swing/1h_1.wav"),
	Sound("devin/blackbetty/weapons/swing/1h_2.wav"),
	Sound("devin/blackbetty/weapons/swing/1h_3.wav")
}

ENT.AttackSounds = {
	Sound("devin/blackbetty/weapons/hamstring/hamstring1.wav"),
	Sound("devin/blackbetty/weapons/hamstring/hamstring2.wav"),
	Sound("devin/blackbetty/weapons/hamstring/hamstring3.wav")
}

ENT.EngageSounds = {
	Sound("devin/blackbetty/player/male/engage_common.wav")
}

ENT.HurtSounds = {
	Sound("devin/blackbetty/player/male/takedamage1.wav"),
	Sound("devin/blackbetty/player/male/takedamage2.wav"),
	Sound("devin/blackbetty/player/male/takedamage3.wav"),
	Sound("devin/blackbetty/player/male/takedamage4.wav")
}

ENT.SwingSounds = {
	Sound("devin/blackbetty/player/male/swing_common1.wav"),
	Sound("devin/blackbetty/player/male/swing_common2.wav"),
	Sound("devin/blackbetty/player/male/swing_common3.wav")
}

ENT.DeathSounds = {
	Sound("devin/blackbetty/player/male/death1.wav"),
	Sound("devin/blackbetty/player/male/death2.wav"),
	Sound("devin/blackbetty/player/male/death3.wav"),
	Sound("devin/blackbetty/player/male/death4.wav"),
}

ENT.SpawnSounds = {
	Sound("devin/blackbetty/player/male/death1.wav"),
}
 
 
function ENT:Initialize()
	self:SetModel(self.Model or "models/devin/rpgdm/testplayer.mdl")
	self:SetModelScale(self.Scale, 0)
	self.tempEquippedItems = self.Gear
	if(self.RandomName)then
		self:SetName(""..self.FirstNames[math.random(1, table.Count(self.FirstNames))].." "..self.LastNames[math.random(1, table.Count(self.LastNames))].."")
	end
	self.Name = self:GetName()
	collision_min = Vector(-8,-8,0)
	collision_max = Vector(8,8,64)
	if(self.Scale > 1)then
		collision_min = collision_min * self.Scale
		collision_max = collision_max * self.Scale
		self.DistanceFromPlayer = self.DistanceFromPlayer + ((self.DistanceFromPlayer * self.Scale)*0.25)
	end
	self:SetCollisionGroup(COLLISION_GROUP_DEBRIS_TRIGGER)
	self:SetCollisionBounds( Vector(-8,-8,0), Vector(8,8,64) ) 
	self:PhysicsInit(SOLID_BBOX)
	self:SetSolid(SOLID_BBOX)
	self:SetHealth(self.HealthMax)
	self:SetMaxHealth(self.HealthMax)
	self.SpawnPos = self:GetPos()
	self.RunSpeed = self.Speed
	self:StartActivity( self.IdleAnim or ACT_IDLE )


	
	if(!self.IsPet)then
		print(self.Model)
		if(self.MainWeapon != "")then
			self.HeldWeapon = ents.Create("prop_physics")
			self.HeldWeapon:SetModel(self.MainWeapon)
			self.HeldWeapon:PhysicsInit(SOLID_VPHYSICS)
			self.HeldWeapon:SetMoveType(MOVETYPE_NONE)
			self.HeldWeapon:SetSolid( SOLID_VPHYSICS )
			self.HeldWeapon:SetParent(self)
			self.HeldWeapon:AddEffects( EF_BONEMERGE )
			self:StartActivity( self.IdleAnim )
		end
		if(self.OffWeapon != "")then
			self.HeldOffWeapon = ents.Create("prop_physics")
			self.HeldOffWeapon:SetModel(self.OffWeapon)
			self.HeldOffWeapon:PhysicsInit(SOLID_VPHYSICS)
			self.HeldOffWeapon:SetMoveType(MOVETYPE_NONE)
			self.HeldOffWeapon:SetSolid( SOLID_VPHYSICS )
			self.HeldOffWeapon:SetParent(self)
			self.HeldOffWeapon:AddEffects( EF_BONEMERGE )
			self:StartActivity( self.IdleAnim )
		end
		--self:EmitSound(self.SpawnSounds[math.random(1, table.Count(self.SpawnSounds))], 100, math.random(95, 110))
	else
		self:SetModel( self.Model or "models/devin/rpgdm/testplayer.mdl")
		self:StartActivity( ACT_IDLE )
		self.IdleSound = CreateSound( self.Entity, self.IdleSoundFile or "npc/antlion_guard/growl_idle.wav", 100, 100)
		self.IdleSound:Play()
	end
	if(self.SpellCaster)then
		self.DistanceFromPlayer = 378
	end
end

function ENT:UpdateInfo()
	self:SetModel(self.Model)
	self:SetModelScale(self.Scale, 0)
	self:SetHealth(self.Health)
	self:SetMaxHealth(self.Health)
	self.SetPos(self.Position)
	self.RunSpeed = self.Speed
	self.InCombat = false
	SetEquipped(self, self.Gear)
	self.tempEquippedItems = self.Gear
end

function ENT:AcceptInput( name, activator, caller, data )
    if (name == "Vendor") then
		if(data >= 1)then
			self.Vendor = true
			self.Aggressive = false
		else
			self.Vendor = false
			self.Aggressive = true
		end
	end
	if (name == "Name") then
		if(data != "" and isstring(data))then
			self:SetName(data)
		end
	end
end

function ENT:Interact(ply)
	if(self.MatchMaker)then

	elseif(self.Vendor)then
		ShowPresetWindow()
	end
end

function ENT:BehaveAct()
	
end

function ENT:BodyUpdate()
	local act = self:GetActivity()

	--
	-- This helper function does a lot of useful stuff for us. 
	-- It sets the bot's move_x move_y pose parameters, sets their animation speed relative to the ground speed, and calls FrameAdvance.
	--
	-- 

	if (act == ACT_HL2MP_RUN || act == self.RunAnim || act == ACT_RUN || act == self.WalkAnim )then
		self:BodyMoveXY()
	end


	-- 
	-- If we're not walking or running we probably just want to update the anim system
	--
	self:FrameAdvance()
end

function ENT:BehaveUpdate( fInterval )
	if ( !self.BehaveThread ) then return end
	
	local ok, message = coroutine.resume( self.BehaveThread )
	if ( ok == false ) then

		self.BehaveThread = nil
		Msg( self, "error: ", message, "\n" );

	end
end

function ENT:OnInjured( dmginfo )
	local dt = dmginfo:GetDamage()
	local attacker = dmginfo:GetAttacker()
	
	if(!self.InCombat && attacker:IsPlayer() && attacker:Alive())then
		self:EmitSound(self.EngageSounds[math.random(1, table.Count(self.EngageSounds))], 100, math.random(95, 110))
		self.Target = attacker
		self.InCombat = true
		attacker.InCombat = true
		self.EngagePos = self:GetPos()
		self.EngageAngle = self:GetAngles()
	end
							
	if(dt > 10 and dt < 20)then
		self:EmitSound("devin/blackbetty/player/body_impact/body_medium_impact_hard"..math.random(1,6)..".wav", 140, 100+math.random(-10,10))
		self:EmitSound(self.HurtSounds[math.random(1, #self.HurtSounds)], 140, 100+math.random(-10,10))
	elseif(dt >= 20 and dt <= 35)then
		self:EmitSound("physics/body/body_medium_break2"..math.random(2,4)..".wav", 140, 100+math.random(-10,10))
		self:EmitSound(self.HurtSounds[math.random(1, #self.HurtSounds)], 140, 100+math.random(-10,10))
		local gore = ents.Create("gore")
		gore:SetPos(self:GetPos() + Vector(0, 0, 40))
		gore:Initialize()
		gore:SetMode("smallhit")
		
	elseif(dt > 35)then
		self:EmitSound("physics/flesh/flesh_squishy_impact_hard"..math.random(2,4)..".wav", 140, 100+math.random(-10,10))
		self:EmitSound(self.HurtSounds[math.random(1, #self.HurtSounds)], 140, 100+math.random(-10,10))
		local gore = ents.Create("gore")
		gore:SetPos(self:GetPos() + Vector(0, 0, 40))
		gore:Initialize()
		gore:SetMode("bighit")
		ParticleEffect( "player_blood", self:GetPos() + Vector(0, 0, 45), Angle(0,0,0), ent )	
	end
	
end




function ENT:OnKilled( info )
	self:Die(info)
	local atk = info:GetAttacker()
	if(atk:IsPlayer())then
		print("Rewarded "..atk:GetName().." "..self.XP.." XP for killing "..self.Name..".")
		AddXP(atk, self.XP, self.Name)
		UpdatePlayerQuest(atk, {"kill", self.MobID, 1})
	end
end

function ENT:Die( dmginfo )
	self.Dead = true
	if(self:Health() <= -25)then
		local gore = ents.Create("gore")
		gore:SetPos(self:GetPos() + Vector(0, 0, 40))
		gore:Initialize()
		gore:SetMode("gib")
		self:SetRenderMode(RENDERMODE_NONE)
	end
	if(!self.IsPet)then
		self:EmitSound(self.DeathSounds[math.random(1, table.Count(self.DeathSounds))], 100, math.random(95, 110))
	else
		self.IdleSound:Stop()
	end
	self:SetCycle(0)
	self:SetSequence( "death_02")
	timer.Simple(0.9, function() 
		self:SetPos(self:GetPos() + ((self:GetAngles():Forward())*(16*self.Scale)))
		self:SetCycle(0)
		self:SetSequence( "zombie_slump_idle_01" )
	end)
	
	-- local ragdoll = ents.Create( "prop_ragdoll" )
	-- self.Corpse = ragdoll
	-- self.Corpse:SetPos( self:GetPos() )
	-- self.Corpse:SetModel( self:GetModel() )
	-- self.Corpse:SetCollisionGroup(COLLISION_GROUP_DEBRIS)
	-- self.Corpse:SetAngles(Angle((self:GetAngles().p), (self:GetAngles().y), self:GetAngles().r))
	-- self.Corpse:Spawn()
	-- self.Corpse:SetName(self:GetName())
	-- self.Corpse:SetMaxHealth(0)
	-- self.Corpse:SetHealth(0)
	-- self.Corpse:SetVelocity(self:GetVelocity())
	-- local bones = self.Corpse:GetPhysicsObjectCount()
	-- for i=0,bones-1 do
		-- self.Corpse:GetPhysicsObjectNum(i):SetVelocity( self:GetVelocity() )
		-- self.Corpse:GetPhysicsObjectNum(i):AddAngleVelocity( Vector( math.random(-1000,1000), math.random(-1000,1000), math.random(-1000,1000)) )
	-- end 
	
	-- if(self.VisibleItems != nil and table.Count(self.VisibleItems) > 0)then
		-- for k, v in pairs(self.VisibleItems)do
			-- v:SetColor(Color(255, 255, 255, 255))
			-- v:SetParent(self.Corpse)
		-- end
	-- end
	
	--timer.Simple(5, function() ragdoll:Remove() end)
	
	timer.Simple(15, function() self:Remove() end)
	
end
 
function ENT:RunBehaviour()
    while ( true ) do
		if(self.Aggressive and !self.Returning and !self.Dead)then
			if(!self.IsPet)then
				if(self.Wander and !InCombat and !self.Target)then
					self:StartActivity( self.WalkAnim )							
					self.loco:SetDesiredSpeed( 65 )
					self:MoveToPos( self:GetPos() + Vector( math.Rand( -1, 1 ), math.Rand( -1, 1 ), 0 ) * 160 )
				end
				local AggroRadius_entities = ents.FindInSphere(self:GetPos(), self.AggroRadius)
				if(!self.Target)then
					for k, v in pairs(AggroRadius_entities or {}) do
						if((v:IsPlayer() or v:GetClass() == "npc_rpgdm") and v.Faction != self.Faction and v:Health() > 0 )then
							self.Target = v
							if(!self.InCombat)then
								self:EmitSound(self.EngageSounds[math.random(1, table.Count(self.EngageSounds))], 100, math.random(95, 110))
								self.InCombat = true
								v.InCombat = true
								self.EngagePos = self:GetPos()
								self.EngageAngle = self:GetAngles()
							end
						end
					end
				else
					if(!self.InCombat)then
						self:EmitSound(self.EngageSounds[math.random(1, table.Count(self.EngageSounds))], 100, math.random(95, 110))
						self.InCombat = true
						self.EngagePos = self:GetPos()
						self.EngageAngle = self:GetAngles()
					end
				end
			else
				self.Target = self.Owner:GetNetworkedEntity("Target")
				if(self.Target and self.Target:IsValid() and self.Target != self)then
					self.Target = self.Owner:GetNetworkedEntity("Target")
					self.InCombat = true
				else
					self.Target = nil
					self.InCombat = false
				end
			end

			
			if(self.Target and self.InCombat and self.Target:IsValid() and self.Target:Health() > 0 and ((self.Target:GetPos() - self:GetPos()):Length()>= self.DistanceFromPlayer))then
				self.Idle = false
				if(!IsPet)then
					self:StartActivity( self.RunAnim )
				else
					self:StartActivity( ACT_RUN )
				end
				self.loco:SetDesiredSpeed( self.RunSpeed )
				local tempdist = 0
				local opts = {  lookahead = 300,
                            tolerance = tempdist,
                            draw = false,
                            maxage = 7,
                            repath = 7    }
				self:MoveToPos( self.Target:GetPos(), opts, self.Target )
			end
			
			if(self.Target and self.InCombat and self.Target:IsValid() and self.Target:Health() > 0 and ((self.Target:GetPos() - self:GetPos()):Length()<= self.DistanceFromPlayer)) then
				if(!self.Idle)then
					if(!IsPet)then
						self:StartActivity( self.IdleAnim )
					else
						self:StartActivity( ACT_IDLE )
					end
					self.Idle = true
				end
				self.loco:FaceTowards( self.Target:GetPos() )
				if(!self.SpellCaster and self.NextAttack <= CurTime())then
					self.NextAttack = CurTime() + self.AttackSpeed
					self:AutoAttack(self.Target)
				elseif(self.SpellCaster and self.NextSpell <= CurTime() and !self:GetNWBool("Casting"))then
					self:CastSpell()
				end
			end
			
			if( self.Target and !(self.Target:Health() > 0) and !self.IsPet)then
				self.Returning = true
				if(!self.IsPet)then
					self:StartActivity( self.RunAnim )
				else
					self:StartActivity( ACT_RUN )
				end
				self.loco:SetDesiredSpeed( self.ReturnSpeed )
				self.Target = nil
				self.Idle = false
				self.InCombat = false
				self:MoveToPos( self.EngagePos )
				self:SetAngles( self.EngageAngle )
				self.Returning = false
			elseif(self.Target and !(self.Target:Health() > 0) and self.IsPet)then
				local opts = {  lookahead = 300,
						tolerance = 16,
						draw = false,
						maxage = 7,
						repath = 7    }
				self.Target = nil
				self.Idle = false
				self.InCombat = false
				self:StartActivity( ACT_RUN )
				self.loco:SetDesiredSpeed( self.RunSpeed )
				self:MoveToPos( self.Owner:GetPos()+(self.Owner:GetAngles():Right()*64), opts, self.Owner )
				
			end
			
			if( self.Target and self.Target:IsValid() and (self.EngagePos - self.Target:GetPos()):Length() >= (self.AggroRadius*10) and !self.IsPet)then
				if(!self.IsPet)then
					self:StartActivity( self.RunAnim )
				else
					self:StartActivity( ACT_RUN )
				end
				self.loco:SetDesiredSpeed( self.ReturnSpeed )
				self.Returning = true
				self.Target = nil
				self.Idle = false
				self.InCombat = false
				self:MoveToPos( self.EngagePos )
				self:SetAngles( self.EngageAngle )
				self.Returning = false
			end
			
			if(!self.InCombat and !self.Idle and !self.IsPet)then
				if(!self.IsPet)then
					self:StartActivity( self.IdleAnim )
				else
					self:StartActivity( ACT_IDLE )
				end
				self.Idle = true
			end
		end
        coroutine.yield()
    end
end

function ENT:CastSpell()
	local spelltarget = nil
	if(self.Healer)then
		local entradius = ents.FindInSphere( self:GetPos(), 512)
		local lowestratio = 1
		for k, v in pairs(entradius)do
			if(!v:IsPlayer() or !v:GetClass() == "npc_rpgdm" or v.Faction != self.Faction or v:Health() >= v:MaxHealth())then
				table.remove(entradius, k)
				k = 0
			end
		end
		for k, v in pairs(entradius)do
			local healthratio = v:MaxHealth()/v:Health()
			if(lowestratio>healthratio)then
				spelltarget = v
			end
		end
		if(spelltarget == nil)then
			return false
		end
	else
		spelltarget = self.Target
	end
	local randspell = self.Spells[math.random(1, #self.Spells)]
	for k, v in pairs(Spells)do
		if(randspell == Spells[k].m_iSpellID)then
			Spells[k]:Cast(self, spelltarget)
			self.NextSpell = CurTime() + Spells[k].m_iCoolDown + 1
			break
		end
	end 
end

function ENT:AutoAttack(target)
	self.Idle = false
	self:SetCycle(0)
	local SwingSoundRand = math.random(1, 2)
	
	if(!self.IsPet)then
		self:RestartGesture(self.AttackAnim)
		self:EmitSound(self.WeaponSounds[math.random(1, table.Count(self.WeaponSounds))], 140, math.random(89, 95))
		coroutine.wait(0.125+(self.AttackDelay or 0))
	else
		self:RestartGesture(ACT_MELEE_ATTACK1)
		coroutine.wait(0.45)
	end
	if(SwingSoundRand == 1 and !self.IsPet)then
		self:EmitSound(self.SwingSounds[math.random(1, table.Count(self.SwingSounds))], 140, math.random(89, 95))
	end
	local dmgamount = math.random(self.MinDamage, self.MaxDamage)
	local dmginfo = DamageInfo()
		dmginfo:SetDamage( dmgamount ) 
		dmginfo:SetDamageType( DMG_GENERIC )
		dmginfo:SetAttacker( self ) 
	target:TakeDamageInfo(dmginfo)
	if(!self.IsPet)then
		target:EmitSound(self.AttackSounds[math.random(1, table.Count(self.AttackSounds))])
	else
		self:EmitSound(self.HitSound or "npc/antlion/attack_single"..math.random(1, 3)..".wav")
	end
end

function ENT:Think()
	if(CLIENT)then
		print(self.Interactable)
	end
end
 
-- List the NPC as spawnable
list.Set( "NPC", "npc_tf2_ghost",     {    Name = "TF2 Ghost", 
                                        Class = "npc_tf2_ghost",
                                        Category = "TF2"   
                                    })